grammar pascal;

options {output=AST;}	// budowa drzewa


tokens {  // korzenie drzew
	BLOCK;
	IDLIST;
	FUNC_CALL;
	PROC_CALL;
	SCALARTYPE;
	TYPELIST;
	VARIANT_TAG;
	VARIANT_TAG_NO_ID;
	VARIANT_CASE;
	CONSTLIST;
	FIELDLIST;
	ARGDECLS;
	VARDECL;
	ARGDECL;
	ARGLIST;
	TYPEDECL;
	FIELD;
	DWIEKROPKI;
}


program
    : naglowek_programu
      blok
      KROPKA!
    ;

naglowek_programu
    : PROGRAM identyfikator (LNAWIAS lista_identyfikatorow PNAWIAS)? SREDNIK -> ^(PROGRAM identyfikator lista_identyfikatorow?)
    ;

identyfikator
    : IDENT
    ;

blok
    : ( czesc_deklarujaca_etykiety
      | czesc_definiujaca_stale
      | czesc_definiujaca_typy
      | czesc_deklarujaca_zmienne
      | czesc_deklarujaca_procedury_i_funkcje
      )*
      instrukcja_zlozona
    ;

czesc_deklarujaca_etykiety
    : LABEL etykieta ( PRZECINEK etykieta )* SREDNIK -> ^(LABEL etykieta+)
    ;

etykieta
    : liczba_calkowita_bez_znaku
    ;

czesc_definiujaca_stale
    : CONST definicja_stalej ( SREDNIK definicja_stalej )* SREDNIK -> ^(CONST definicja_stalej+)
    ;

definicja_stalej
    : identyfikator ROWNOSC stala -> ^(ROWNOSC identyfikator stala)
    ;

stala
    : liczba_bez_znaku
    | znak liczba_bez_znaku -> ^(znak liczba_bez_znaku)
    | identyfikator
    | znak identyfikator -> ^(znak identyfikator)
    | napis
    ;

liczba_bez_znaku
    : liczba_calkowita_bez_znaku
    | liczba_rzeczywista_bez_znaku
    ;

liczba_calkowita_bez_znaku
    : NUM_INT
    ;

liczba_rzeczywista_bez_znaku
    : NUM_REAL
    ;

znak
    : PLUS | MINUS
    ;

napis
    : STRING_LITERAL
    ;

czesc_definiujaca_typy
    : TYPE definicja_typu ( SREDNIK definicja_typu )* SREDNIK -> ^(TYPE definicja_typu+)
    ;

definicja_typu
    : identyfikator ROWNOSC ( nowy_typ ) -> ^(TYPEDECL identyfikator nowy_typ)
    ;

nowy_typ
    : nowy_typ_prosty
    | nowy_typ_strukturalny
    | nowy_typ_wskaznikowy
    ;

nowy_typ_prosty
    : typ_wyliczeniowy
    | typ_okrojony
    | identyfikator_typu
    | stringtype
    ;

typ_wyliczeniowy
    : LNAWIAS lista_identyfikatorow PNAWIAS -> ^(SCALARTYPE lista_identyfikatorow)
    ;

typ_okrojony
    : stala DWIEKROPKI stala -> ^(DWIEKROPKI stala stala)
    ;

identyfikator_typu
    : identyfikator
    | CHAR
    | BOOLEAN
    | INTEGER
    | REAL
    | STRING
    ;

nowy_typ_strukturalny
    : PACKED typ_strukturalny_niespakowany -> ^(PACKED typ_strukturalny_niespakowany)
    | typ_strukturalny_niespakowany
    ;

typ_strukturalny_niespakowany
    : typ_tablicowy
    | typ_rekordowy
    ;

stringtype
    : STRING^ LNAWIAS! (identyfikator|liczba_bez_znaku) PNAWIAS!
    ;

typ_tablicowy
    : ARRAY LNAWIASKWADRATOWY lista_typow_indeksowych PNAWIASKWADRATOWY OF typ_skladowy -> ^(ARRAY lista_typow_indeksowych typ_skladowy)
    | ARRAY LNAWIAS2 lista_typow_indeksowych PNAWIAS2 OF typ_skladowy -> ^(ARRAY lista_typow_indeksowych typ_skladowy)
	;

lista_typow_indeksowych
	: typ_indeksowy ( PRZECINEK typ_indeksowy )* -> ^(TYPELIST typ_indeksowy+)
	;

typ_indeksowy
    : nowy_typ_prosty
    ;

typ_skladowy
    : nowy_typ
    ;

typ_rekordowy
    : RECORD lista_pol END -> ^(RECORD lista_pol)
    ;

lista_pol
    : (	czesc_stala ( SREDNIK czesc_zmienna | SREDNIK )? -> ^(FIELDLIST czesc_stala czesc_zmienna?)
      | czesc_zmienna -> ^(FIELDLIST czesc_zmienna)
      )
    ;

czesc_stala
    : sekcja_rekordu ( SREDNIK! sekcja_rekordu )*
    ;

sekcja_rekordu
    : lista_identyfikatorow DWUKROPEK nowy_typ -> ^(FIELD nowy_typ lista_identyfikatorow)
    ;

czesc_zmienna
    : CASE selektor_wariantu OF wariant ( SREDNIK wariant | SREDNIK )* -> ^(CASE selektor_wariantu wariant+)
    ;

selektor_wariantu
    :
	identyfikator DWUKROPEK identyfikator_typu  -> ^(VARIANT_TAG identyfikator identyfikator_typu)
    |	identyfikator_typu -> ^(VARIANT_TAG_NO_ID identyfikator_typu)
    ;

wariant
    :	lista_stalych_wyboru DWUKROPEK LNAWIAS lista_pol PNAWIAS -> ^(VARIANT_CASE lista_stalych_wyboru lista_pol)
    ;

nowy_typ_wskaznikowy
    : WSKAZNIK identyfikator_typu -> ^(WSKAZNIK identyfikator_typu)
    ;

czesc_deklarujaca_zmienne
    : VAR deklaracja_zmiennej ( SREDNIK deklaracja_zmiennej )* SREDNIK -> ^(VAR deklaracja_zmiennej+)
    ;

deklaracja_zmiennej
    :	lista_identyfikatorow DWUKROPEK nowy_typ -> ^(VARDECL nowy_typ lista_identyfikatorow)
    ;

czesc_deklarujaca_procedury_i_funkcje
    : deklaracja_procedury_lub_funkcji SREDNIK!
    ;

deklaracja_procedury_lub_funkcji
    : deklaracja_procedury
    | deklaracja_funkcji
    ;

deklaracja_procedury
    : PROCEDURE identyfikator (lista_parametrow_formalnych)? SREDNIK blok -> ^(PROCEDURE identyfikator lista_parametrow_formalnych? blok)
    ;

lista_parametrow_formalnych
    : LNAWIAS sekcja_parametrow_formalnych ( SREDNIK sekcja_parametrow_formalnych )* PNAWIAS -> ^(ARGDECLS sekcja_parametrow_formalnych+)
    ;

sekcja_parametrow_formalnych
    : grupa_parametrow
    | VAR^ grupa_parametrow
    ;

grupa_parametrow!
    :	lista_identyfikatorow DWUKROPEK identyfikator_typu -> ^(ARGDECL identyfikator_typu lista_identyfikatorow)
    ;

lista_identyfikatorow
    : identyfikator ( PRZECINEK identyfikator )* -> ^(IDLIST identyfikator+)
    ;

lista_stalych_wyboru
    : stala ( PRZECINEK stala )* -> ^(CONSTLIST stala+)
    ;

deklaracja_funkcji
    : FUNCTION identyfikator (lista_parametrow_formalnych)? DWUKROPEK typ_wyniku SREDNIK  blok -> ^(FUNCTION identyfikator lista_parametrow_formalnych? typ_wyniku blok)
    ;

typ_wyniku
    : identyfikator_typu
    ;

instrukcja
    : etykieta DWUKROPEK instrukcja_bez_etykiety -> ^(DWUKROPEK etykieta instrukcja_bez_etykiety)
    | instrukcja_bez_etykiety
    ;

instrukcja_bez_etykiety
    : instrukcja_prosta
    | instrukcja_strukturalna
    ;

instrukcja_prosta
    : instrukcja_przypisania
    | instrukcja_procedury
    | instrukcja_skoku
    | instrukcja_pusta
    ;

instrukcja_przypisania
    : zmienna PRZYPISANIE wyrazenie -> ^(PRZYPISANIE zmienna wyrazenie)
    ;

/*
	Byc moze potrzebna tu bedzie zmiana
*/
zmienna
    : 	identyfikator
      (	LNAWIASKWADRATOWY^ wyrazenie ( PRZECINEK! wyrazenie)* PNAWIASKWADRATOWY!
      | LNAWIAS2^ wyrazenie ( PRZECINEK! wyrazenie)* PNAWIAS2!
      | KROPKA^ identyfikator
      | WSKAZNIK^
      )*
    ;

wyrazenie
    : proste_wyrazenie
	  ( (ROWNOSC^ | NIEROWNOSC^ | MNIEJSZY^ | MNIEJSZYLUBROWNY^ | WIEKSZYLUBROWNY^ | WIEKSZY^ | IN^) proste_wyrazenie )*
    ;

proste_wyrazenie
    : skladnik ( (PLUS^ | MINUS^ | OR^) skladnik )*
    ;

skladnik
	: czynnik ( (GWIAZDKA^ | SLASH^ | DIV^ | MOD^ | AND^) czynnik )*
    ;

czynnik
    : (PLUS^|MINUS^)? czynnik_bez_znaku
    ;

czynnik_bez_znaku
    : zmienna
    | LNAWIAS! wyrazenie PNAWIAS!
    | nazewnik_funkcji
    | stala_bez_znaku
    | NOT^ czynnik_bez_znaku
    ;

stala_bez_znaku
    : liczba_bez_znaku
    | napis
    | NIL
    ;

nazewnik_funkcji
    : identyfikator LNAWIAS lista_parametrow_aktualnych PNAWIAS -> ^(FUNC_CALL identyfikator lista_parametrow_aktualnych)
    ;

lista_parametrow_aktualnych
    : parametr_aktualny ( PRZECINEK parametr_aktualny )* -> ^(ARGLIST parametr_aktualny+)
    ;
    
instrukcja_procedury
    : identyfikator ( LNAWIAS lista_parametrow_aktualnych PNAWIAS )? -> ^(PROC_CALL identyfikator lista_parametrow_aktualnych?)
    ;

parametr_aktualny
    : wyrazenie
    ;

instrukcja_skoku
    : GOTO^ etykieta
    ;

instrukcja_pusta
    :
    ;

instrukcja_strukturalna
    : instrukcja_zlozona
    | instrukcja_warunkowa
    | instrukcja_iteracyjna
    | instrukcja_wiazaca
    ;

instrukcja_zlozona
    : BEGIN!
		ciag_instrukcji
      END!
    ;

ciag_instrukcji
    : instrukcja ( SREDNIK instrukcja )* -> ^(BLOCK instrukcja*)
    ;

instrukcja_warunkowa
    : instrukcja_jesli
    | instrukcja_wyboru
    ;

instrukcja_jesli
    : IF wyrazenie THEN instrukcja
      (
		: ELSE instrukcja
	  )? -> ^(IF wyrazenie instrukcja instrukcja?)
    ;

instrukcja_wyboru
    : CASE wyrazenie OF
        element_listy_wyboru ( SREDNIK element_listy_wyboru )*
      ( SREDNIK ELSE ciag_instrukcji )?
      END -> ^(CASE wyrazenie element_listy_wyboru+ ciag_instrukcji?)
    ;

element_listy_wyboru
    : lista_stalych_wyboru DWUKROPEK instrukcja -> ^(DWUKROPEK lista_stalych_wyboru instrukcja)
    ;

instrukcja_iteracyjna
    : instrukcja_dopoki
    | instrukcja_powtarzaj
    | instrukcja_dla
    ;

instrukcja_dopoki
    : WHILE wyrazenie DO instrukcja -> ^(WHILE wyrazenie instrukcja)
    ;

instrukcja_powtarzaj
    : REPEAT ciag_instrukcji UNTIL wyrazenie -> ^(REPEAT ciag_instrukcji wyrazenie)
    ;

instrukcja_dla
    : FOR identyfikator PRZYPISANIE sekwencja_for DO instrukcja -> ^(FOR identyfikator sekwencja_for instrukcja)
    ;

sekwencja_for
    : wartosc_poczatkowa (TO^ | DOWNTO^) wartosc_koncowa
    ;

wartosc_poczatkowa
    : wyrazenie
    ;

wartosc_koncowa
    : wyrazenie
    ;

instrukcja_wiazaca
    : WITH^ lista_zmiennych_rekordowych DO! instrukcja
    ;

lista_zmiennych_rekordowych
    : zmienna ( PRZECINEK! zmienna )*
    ;

  AND              
  	:	 'and'             ;
  ARRAY            
  	:	 'array'           ;
  BEGIN            
  	:	 'begin'           ;
  BOOLEAN          
  	:	 'boolean'         ;
  CASE             
  	:	 'case'            ;
  CHAR             
  	:	 'char'            ;
  CONST            
  	:	 'const'           ;
  DIV              
  	:	 'div'             ;
  DO               
  	:	 'do'              ;
  DOWNTO           
  	:	 'downto'          ;
  ELSE             
  	:	 'else'            ;
  END              
  	:	 'end'             ;
  FILE             
  	:	 'file'            ;
  FOR              
  	:	 'for'             ;
  FUNCTION         
  	:	 'function'        ;
  GOTO             
  	:	 'goto'            ;
  IF               
  	:	 'if'              ;
  IN               
  	:	 'in'              ;
  INTEGER          
  	:	 'integer'         ;
  LABEL            
  	:	 'label'           ;
  MOD              
  	:	 'mod'             ;
  NIL              
  	:	 'nil'             ;
  NOT              
  	:	 'not'             ;
  OF               
  	:	 'of'              ;
  OR               
  	:	 'or'              ;
  	
  PACKED        
  	:	 'packed'       ;
  	
  PROCEDURE        
  	:	 'procedure'       ;
  PROGRAM          
  	:	 'program'         ;
  REAL             
  	:	 'real'            ;
  RECORD           
  	:	 'record'          ;
  REPEAT           
  	:	 'repeat'          ;
  THEN             
  	:	 'then'            ;
  TO               
  	:	 'to'              ;
  TYPE             
  	:	 'type'            ;
  UNTIL            
  	:	 'until'           ;
  VAR              
  	:	 'var'             ;
  WHILE            
  	:	 'while'           ;
  WITH             
  	:	 'with'            ;
  STRING           
  	:	 'string'          ;

//----------------------------------------------------------------------------
// OPERATORY
//----------------------------------------------------------------------------
PLUS            : '+'   ;
MINUS           : '-'   ;
GWIAZDKA            : '*'   ;
SLASH           : '/'   ;
PRZYPISANIE          : ':='  ;
PRZECINEK           : ','   ;
SREDNIK            : ';'   ;
DWUKROPEK           : ':'   ;
ROWNOSC           : '='   ;
NIEROWNOSC       : '<>'  ;
MNIEJSZY              : '<'   ;
MNIEJSZYLUBROWNY              : '<='  ;
WIEKSZYLUBROWNY              : '>='  ;
WIEKSZY              : '>'   ;
LNAWIAS          : '('   ;
PNAWIAS          : ')'   ;
LNAWIASKWADRATOWY          : '['   ;
LNAWIAS2         : '(.'  ; 
PNAWIASKWADRATOWY         : ']'   ;
PNAWIAS2         : '.)'  ;
WSKAZNIK         : '^'   ;
AT              : '@'   ;
KROPKA             : '.'  ('.' { $type = DWIEKROPKI; })? ;
//DWIEKROPKI          : '..' ;
LNAWIASKLAMROWY          : '{' ;
PNAWIASKLAMROWY          : '}' ;


WS      : ( ' '
		|	'\t'
		|	'\f'
		|	(	'\r\n'  // DOS
			|	'\r'    // Macintosh
			|	'\n'    // Unix
			)
		)
		{skip();}
	;


KOMENTARZ_1
        : '(*'
		   ( 
		   :    '*'
		   |	'\r' '\n'
		   |	'\r'	
		   |	'\n'		
           |   ~('*' | '\n' | '\r')
		   )*
          '*)'
          {skip();}
	;

KOMENTARZ_2
        :  '{' (
            :   '\r' '\n'    
		    |	'\r'			
		    |	'\n'		
            |   ~('}' | '\n' | '\r')
		    )*
           '}'
           {skip();}
	;
	
IDENT
	:	('a'..'z' | 'A'..'Z') ('a'..'z'|'A'..'B'|'0'..'9'|'_')* 
	;

STRING_LITERAL
	: '\'' ('\'\'' | ~('\''))* '\'' 
	;
	
NUM_INT	
	:	('0'..'9')+
	;
	
NUM_REAL 
	:	('0'..'9')+ (KROPKA ('0'..'9')+)? (EXPONENT)?
	;

//protected
EXPONENT
	:	('e') ('+'|'-')? ('0'..'9')+
	;
